#include <unistd.h>
#include <stdio.h>
#include <string.h>

#include "ak_common.h"
#include "ak_thread.h"
#include "ak_drv_ir.h"
#include "ak_vi.h"
#include "ak_misc.h"

#ifdef CONFIG_ONVIF_SUPPORT
#include "ak_onvif.h"
#endif

#ifdef CONFIG_RTSP_SUPPORT
#include "ak_rtsp.h"
#endif

#ifdef CONFIG_DANA_SUPPORT
#include "ak_dana.h"
#endif

#define AK_IPC_START_TIME	"/tmp/ak_ipc_start_time"

enum day_ctrl_level {
	DAY_LEVEL_RESERVED = 0x00,
	DAY_LEVEL_HH,		//high-high
	DAY_LEVEL_HL,		//high-low
	DAY_LEVEL_LH,		//low-high
	DAY_LEVEL_LL,		//low-low
	DAY_LEVEL_MAX
};

struct ak_misc {
    int ircut_run_flag;	    //photosensitive and ircut switch run flag
    int ps_switch_enable;   //store photosensitive switch status
    int day_level_ctrl;		//day level default led-ircut config
    int ipc_run_flag;		//ipc run flag
    void *vi_handle;		//global vi handle
    ak_pthread_t ircut_tid;
};

static struct ak_misc misc_ctrl = {0};
static const char misc_version[] = "app_misc V2.3.00";

/*
 * photosensitive_switch_th - according to photosensitive status
 *                            to switch ircut and video
 */
static void *photosensitive_switch_th(void *arg)
{
	long int tid = ak_thread_get_tid();
	int ir_val = 0;
	int prev_state = -1;

	ak_print_normal_ex("Thread start, id: %ld\n", tid);
	ak_thread_set_name("PS_switch");

	misc_ctrl.ps_switch_enable = AK_TRUE;
	/* get ir state and switch day-night */
	while (misc_ctrl.ircut_run_flag) {
		if (misc_ctrl.ps_switch_enable) {
			ir_val = ak_drv_ir_get_input_level();
			if (prev_state != ir_val) {
		        ak_print_normal_ex("prev_state=%d, ir_val=%d\n",
			        prev_state, ir_val);
				ak_misc_set_video_day_night(misc_ctrl.vi_handle, ir_val,
				    misc_ctrl.day_level_ctrl);
				prev_state = ir_val;	//store new state
			}
		}
		ak_sleep_ms(5*1000);
	}

	ak_print_normal_ex("Thread exit, id: %ld\n", tid);
	ak_thread_exit();
	return NULL;
}

/*
 * gop_switch_notify - call all register callback to switch gop
 */
static void gop_switch_notify(void)
{
#ifdef CONFIG_ONVIF_SUPPORT
    ak_onvif_switch_gop();
#endif

#ifdef CONFIG_RTSP_SUPPORT
    ak_rtsp_switch_gop();
#endif

#ifdef CONFIG_DANA_SUPPORT
    ak_dana_switch_gop();
#endif
}

/**
 * ak_misc_get_version - get misc version
 * return: version string
 */
const char* ak_misc_get_version(void)
{
	return misc_version;
}

/**
 * ak_misc_ipc_first_run: ipc is first run or not
 * return: 1 first run, 0 not first run
 */
int ak_misc_ipc_first_run(void)
{
	if(misc_ctrl.ipc_run_flag)
		return 1;

	/* ipc is not first start up */
	if (access(AK_IPC_START_TIME, W_OK) == 0)
		return 0;

	time_t t;
	char start_time[100] = {0};

	time(&t);
	sprintf(start_time, "ipc start time: %s\n", ctime(&t));

	FILE *fp = fopen(AK_IPC_START_TIME, "a+");
	fwrite(start_time, 1, strlen(start_time), fp);
	fclose(fp);

	misc_ctrl.ipc_run_flag = AK_TRUE;

	return 1;
}

/**
 * ak_misc_set_video_day_night: set video day or night mode, according to IR value
 * @vi_handle: opened vi handle
 * @ir_val: IR value, [0, 1]
 * @day_level: day control level, [1, 4]
 * return: 0 success, -1 failed
 */
int ak_misc_set_video_day_night(void *vi_handle, int ir_val, int day_level)
{
	if (!vi_handle) {
		return AK_FAILED;
	}

	int day_val = 0;

	switch (day_level) {
	case DAY_LEVEL_HH:
		ak_drv_ir_set_ircut(ir_val);
		day_val = ir_val;
		break;
	case DAY_LEVEL_HL:
		ak_drv_ir_set_ircut(!ir_val);
		day_val = ir_val;
		break;
	case DAY_LEVEL_LH:
		ak_drv_ir_set_ircut(!ir_val);
		day_val = !ir_val;
		break;
	case DAY_LEVEL_LL:
		ak_drv_ir_set_ircut(ir_val);
		day_val = !ir_val;
		break;
	default:
		return AK_FAILED;
	}

	int ret = AK_FAILED;
	if (day_val) {
		ak_print_normal_ex("now set to day\n");
		ret = ak_vi_switch_mode(vi_handle, VI_MODE_DAY_OUTDOOR);
	} else {
		ak_print_normal_ex("now set to night\n");
		ret = ak_vi_switch_mode(vi_handle, VI_MODE_NIGHTTIME);
	}

	ak_sleep_ms(300);
	/* to notify av mode to modify gop */
	gop_switch_notify();

	return ret;
}

/**
 * ak_misc_start_photosensitive_switch: start photosensitive switch
 * @day_ctrl: day control level, [1, 4]
 * return: 0 success, -1 failed
 */
int ak_misc_start_photosensitive_switch(int day_ctrl)
{
	if ((day_ctrl > DAY_LEVEL_RESERVED)
		&& (day_ctrl < DAY_LEVEL_MAX)) {
		misc_ctrl.day_level_ctrl = day_ctrl;
	} else {
		return AK_FAILED;
	}

	if (misc_ctrl.ircut_run_flag)
		return AK_SUCCESS;

	ak_drv_ir_init();
	misc_ctrl.vi_handle = ak_vi_get_handle(VIDEO_DEV0);
	misc_ctrl.ircut_run_flag = AK_TRUE;

	return ak_thread_create(&misc_ctrl.ircut_tid, photosensitive_switch_th,
			NULL, 100 *1024, -1);
}

/**
 * ak_misc_switch_photosensitive_ircut - photosensitive and ircut switch
 * @enable[IN]: 0 disable AEC, 1 enable AEC
 * return: 0 success, -1 failed
 * notes:
 */
void ak_misc_switch_photosensitive_ircut(int enable)
{
	ak_print_normal_ex("set photosensitive switch %s.\n",
			enable == 1 ? "enable" : "disable");
	misc_ctrl.ps_switch_enable = enable;
}

void ak_misc_stop_photosensitive_switch(void)
{
	misc_ctrl.ircut_run_flag = AK_FALSE;
	ak_print_normal_ex("set pircut_th_runflag to 0\n");

    ak_print_notice_ex("join photosensitive switch thread...\n");
	ak_thread_join(misc_ctrl.ircut_tid);
	ak_print_notice_ex("photosensitive switch thread join OK\n");
}
